/*
-----------------------------------------------------------------------------
This source file is part of Labor3D
(Labor 3D Graphics Engine)

Copyright (c) 2009-2020 Rock Mao
* creator : Rock Mao
* created : 2009-5-2   21:45
* filename: LaborCore.h

-----------------------------------------------------------------------------
*/

#ifndef __LABORCORE_H__
#define __LABORCORE_H__
#include "LaborCoreDef.h"
#include "./Common/LaborSingleton.h"
#include "./Plugin/LaborDynLib.h"
#include "./Plugin/LaborPlugin.h"
#include <vector>
#include <algorithm>
NAMESPACE_LABOR3D_BEGIN

#pragma  warning(disable : 4251)
class ILRenderSystem;
typedef std::vector<ILRenderSystem*> RenderSystemList;

class LABORCORE_API CLCore : public CLSingleton<CLCore>
{
	friend class ILRenderSystem;
public:
	typedef std::vector<CLDynLib*> PluginLibList;
	typedef std::vector<CLPlugin*> PluginInstanceList;
	typedef std::vector<CLString> StringVector;

private:
	RenderSystemList m_Renderers;
	ILRenderSystem* m_pCurrentRenderer;
protected:
	/// List of plugin DLLs loaded
	PluginLibList m_PluginLibs;
	/// List of CLPlugin instances registered
	PluginInstanceList m_Plugins;
	/// Are we initialised yet?
	bool mIsInitialised;

public:
	CLCore();
	~CLCore();

	void initialise();
	void destory(void);
	/** Returns whether the system is initialised or not. */
	bool isInitialised(void) const { return mIsInitialised; }

	///////////////////////////////////////////////////////////////////////////////////////////
	////                                  Render function                                 /////
	////                                                                                  ////
	//////////////////////////////////////////////////////////////////////////////////////////
	void addRenderSystem( ILRenderSystem* pNewRenderer );
	void setRenderSystem( ILRenderSystem* pRenderer );
	ILRenderSystem* getRenderSystem();
	/** Retrieve a list of the available render systems.
	@remarks
	Retrieves a pointer to the list of available renderers as a
	list of RenderSystem subclasses. Can be used to build a
	custom settings dialog.
	*/
	RenderSystemList* getAvailableRenderers(void);

	/** Retrieve a pointer to the render system by the given name
	@param
	name Name of the render system intend to retrieve.
	@returns
	A pointer to the render system, <b>NULL</b> if no found.
	*/
	ILRenderSystem* getRenderSystemByName(const CLString& name);


	///////////////////////////////////////////////////////////////////////////////////////////
	////                                  Plugin function                                 /////
	////                                                                                  ////
	//////////////////////////////////////////////////////////////////////////////////////////
	/** Manually load a CLPlugin contained in a DLL / DSO.
	@remarks
	Plugins embedded in DLLs can be loaded at startup using the plugin 
	configuration file specified when you create Root (default: plugins.cfg).
	This method allows you to load plugin DLLs directly in code.
	The DLL in question is expected to implement a dllStartPlugin 
	method which instantiates a CLPlugin subclass and calls Root::installPlugin.
	It should also implement dllStopPlugin (see Root::unloadPlugin)
	@param pluginName Name of the plugin library to load
	*/
	void loadPlugin(const CLString& pluginName);
	/** Manually unloads a CLPlugin contained in a DLL / DSO.
	@remarks
	CLPlugin DLLs are unloaded at shutdown automatically. This method 
	allows you to unload plugins in code, but make sure their 
	dependencies are decoupled first. This method will call the 
	dllStopPlugin method defined in the DLL, which in turn should call
	Root::uninstallPlugin.
	@param pluginName Name of the plugin library to unload
	*/
	void unloadPlugin(const CLString& pluginName);
	/** Install a new plugin.
	@remarks
	This installs a new extension to OGRE. The plugin itself may be loaded
	from a DLL / DSO, or it might be statically linked into your own 
	application. Either way, something has to call this method to get
	it registered and functioning. You should only call this method directly
	if your plugin is not in a DLL that could otherwise be loaded with 
	loadPlugin, since the DLL function dllStartPlugin should call this
	method when the DLL is loaded. 
	*/
	void installPlugin(CLPlugin* plugin);
	/** Uninstall an existing plugin.
	@remarks
	This uninstalls an extension to OGRE. Plugins are automatically 
	uninstalled at shutdown but this lets you remove them early. 
	If the plugin was loaded from a DLL / DSO you should call unloadPlugin
	which should result in this method getting called anyway (if the DLL
	is well behaved).
	*/
	void uninstallPlugin(CLPlugin* plugin);
	/** Gets a read-only list of the currently installed plugins. */
	const PluginInstanceList& getInstalledPlugins() const { return m_Plugins; }
	/** Method reads a plugins configuration file and instantiates all
	plugins.
	@param
	pluginsfile The file that contains plugins information.
	Defaults to "plugins.cfg".
	*/
	void loadPlugins( const CLString& pluginsfile = L"plugins.cfg" );
	/** Initialise all loaded plugins - allows plugins to perform actions
	once the renderer is initialised.
	*/
	void initialisePlugins();
	/** Shuts down all loaded plugins - allows things to be tidied up whilst
	all plugins are still loaded.
	*/
	void destoryPlugins();

	/** Unloads all loaded plugins.
	*/
	void unloadPlugins();


	//////////////////////////////////////////////////////////////////////////////////////
};

inline CLCore* GetLaborCore() { return CLCore::getSingletonPtr(); }
inline ILRenderSystem * GetRenderSystem() { return GetLaborCore()->getRenderSystem(); }
NAMESPACE_LABOR3D_END


#endif /// __LABORCORE_H__